﻿using Castle.Core.Internal;
using Castle.Core.Logging;
using Castle.Facilities.Startable;
using Castle.MicroKernel.Registration;
using Castle.Services.Logging.Log4netIntegration;
using Castle.Windsor;
using Inovout.Resources;
using Inovout.Runtime;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Inovout
{
    public partial class ComponentRegistry
    {
        private IWindsorContainer container;

        internal IWindsorContainer Container
        {
            get { return container; }
        }
        private List<ComponentAssembly> componentAssemblys;

        private AppDomain appDomain;

        private IApplication application;
        public void Dispose()
        {
            container.Dispose();
            componentAssemblys.Clear();
        }
        private ComponentRegistry(IApplication application)
        {
            this.application = application;
            this.appDomain = AppDomain.CurrentDomain;
            componentAssemblys = new List<ComponentAssembly>();
            container = new WindsorContainer();
            RegisterLogger();
        }
        private void RegisterLogger()
        {
            ConfigFile log4netConfigFile = new ConfigFile("log4net");
            IExtendedLoggerFactory loggerFactory = null;
            if (log4netConfigFile.HasCustomConfigFile())
            {
                loggerFactory = new ExtendedLog4netFactory(log4netConfigFile.FileFullName);
            }
            else
            {
                using (Stream log4NetConfigStream = log4netConfigFile.Read())
                {
                    loggerFactory = new ExtendedLog4netFactory(log4NetConfigStream);
                }
            }
            string defautlLogName = "Default";
            container.Register(
                    Component.For<IExtendedLoggerFactory>().NamedAutomatically("iloggerfactory").Instance(loggerFactory),
                    Component.For<ILoggerFactory>().NamedAutomatically("iloggerfactory.base").Instance(loggerFactory));


            IExtendedLogger defaultLogger = loggerFactory.Create(defautlLogName);
            container.Register(Component.For<IExtendedLogger>().NamedAutomatically("ilogger.default").Instance(defaultLogger),
                            Component.For<ILogger>().NamedAutomatically("ilogger.default.base").Instance(defaultLogger));

            container.Kernel.Resolver.AddSubResolver(new LoggerResolver(loggerFactory, defautlLogName));

        }
        private void Init()
        {
            container.Register(Component.For<IApplication>().Instance(application));
            container.AddFacility<StartableFacility>(f => f.DeferredStart());

            IAssemblyProvider frameworkAssemblyProvider = new AssemblyFilter(
              Path.GetDirectoryName(new Uri(typeof(ComponentRegistry).Assembly.CodeBase).LocalPath)).WithKeyToken(typeof(ComponentRegistry).Assembly.GetName().GetPublicKeyToken());
            IEnumerable<Assembly> frameworkAssemblies = frameworkAssemblyProvider.GetAssemblies();
            foreach (Assembly frameworkAssembly in frameworkAssemblies)
            {
                AddComponentAssembly(frameworkAssembly);
            }
            appDomain.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyLoadHandler);

            IEnumerable<Assembly> moduleAssemblies = appDomain.GetAssemblies().Except(frameworkAssemblies);
            foreach (Assembly assembly in moduleAssemblies)
            {
                AddComponentAssembly(assembly);
            }
        }

        private void AddComponentAssembly(Assembly assembly)
        {
            ComponentAssembly componentAssembly = new ComponentAssembly(this, assembly);
            componentAssembly.Load();
            componentAssemblys.Add(componentAssembly);
        }
        private void AssemblyLoadHandler(object sender, AssemblyLoadEventArgs args)
        {
            if (!args.LoadedAssembly.IsDynamic)
            {
                AddComponentAssembly(args.LoadedAssembly);
            }
        }











    }

}
